package edu.upb.acs.jobsmaps.activity;

import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.*;
import edu.upb.acs.jobsmaps.R;
import edu.upb.acs.jobsmaps.activity.adapter.MainGridViewAdapter;
import edu.upb.acs.jobsmaps.activity.adapter.MapMarkerAdapter;
import edu.upb.acs.jobsmaps.activity.details.ViewCompanyDetailsActivity;
import edu.upb.acs.jobsmaps.activity.details.ViewJobDetailsActivity;
import edu.upb.acs.jobsmaps.activity.search.SearchCompanyActivity;
import edu.upb.acs.jobsmaps.activity.search.SearchCompanyActivityVoice;
import edu.upb.acs.jobsmaps.activity.search.SearchJobActivity;
import edu.upb.acs.jobsmaps.activity.search.SearchJobActivityVoice;
import edu.upb.acs.jobsmaps.database.task.SearchCompaniesTask;
import edu.upb.acs.jobsmaps.database.task.SearchJobsTask;
import edu.upb.acs.jobsmaps.entity.Company;
import edu.upb.acs.jobsmaps.entity.Job;
import edu.upb.acs.jobsmaps.voice.VoiceUtils;
import edu.upb.acs.jobsmaps.voice.WordList;
import edu.upb.acs.jobsmaps.voice.WordMatcher;

import java.util.*;


public class MainScreenActivity extends FragmentActivity {
	private static final int VOICE_RECOGNITION_REQUEST_CODE = 1001;

	private static final String TAG = MainScreenActivity.class.getName();
	GridView gridView;
	private GoogleMap googleMap;

	static final String[] APP_MENU = new String[]{"Job Search", "Company Search", "Speak", "Admin"};

	private static Map<Integer, Job> jobs = new HashMap<>();
	private static Map<Integer, Company> companies = new HashMap<>();

	Collection<MarkerOptions> markers = new ArrayList<>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main_activity3);

		initializeOptionsMenu();

		initializeGoogleMap();
	}

	private void initializeOptionsMenu() {
		final Activity activity = this;
		gridView = (GridView) findViewById(R.id.gridView);
		gridView.setAdapter(new MainGridViewAdapter(this, APP_MENU));

		gridView.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View v,
									int position, long id) {
				String option = APP_MENU[position];

				if (option.equals("Job Search")) {
					Intent i = new Intent(MainScreenActivity.this,
							SearchJobActivityVoice.class);
					startActivity(i);
				} else if (option.equals("Company Search")) {
					Intent i = new Intent(MainScreenActivity.this,
							SearchCompanyActivityVoice.class);
					startActivity(i);
				} else if (option.startsWith("Admin")) {
					Intent i = new Intent(MainScreenActivity.this,
							AdministrationActivity.class);
					startActivity(i);
				} else if (option.startsWith("Speak")) {
					VoiceUtils.speak(null, null, activity);
				}
			}
		});
	}

	private void initializeGoogleMap() {
		// Getting Google Play availability status
		int status = GooglePlayServicesUtil
				.isGooglePlayServicesAvailable(getBaseContext());

		// Showing status
		if (status != ConnectionResult.SUCCESS) {

			// Google Play Services are not available
			int requestCode = 10;
			Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this,
					requestCode);
			dialog.show();
		} else {
			// Getting reference to the SupportMapFragment of activity_main.xml
			SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager()
					.findFragmentById(R.id.map);

			// Getting GoogleMap object from the fragment
			googleMap = fm.getMap();

			// Enabling MyLocation Layer of Google Map
			googleMap.setMyLocationEnabled(true);

			// Setting a custom info window adapter for the google map
			LayoutInflater layoutInflater = getLayoutInflater();

			googleMap.setInfoWindowAdapter(new MapMarkerAdapter(layoutInflater, jobs, companies, getContentResolver(), getApplicationContext()));

			googleMap.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
				public void onInfoWindowClick(Marker arg0) {
					System.out.println("Marker = " + arg0.getId());
					String snippet = arg0.getSnippet();
					if (null != snippet) {
						if (snippet.startsWith("J")) {
							Intent intent = new Intent(getBaseContext(), ViewJobDetailsActivity.class);
							String jobId = snippet.substring(1);

							final Job job = jobs.get(Integer.valueOf(jobId));
							Log.d(TAG, "[Marker] snippet = " + snippet);
							Log.d(TAG, "[Marker] job id = " + job.getId());

							intent.putExtra("job_id", String.valueOf(job.getId()));

							startActivity(intent);
						} else if (snippet.startsWith("C")) {
							Intent intent = new Intent(getBaseContext(), ViewCompanyDetailsActivity.class);
							String companyId = snippet.substring(1);

							final Company company = companies.get(Integer.valueOf(companyId));
							Log.d(TAG, "[Marker] snippet = " + snippet);
							Log.d(TAG, "[Marker] company id = " + company.getId());

							intent.putExtra("company_id", String.valueOf(company.getId()));

							startActivity(intent);
						} else {
							Log.e(TAG, "NO VALID SNIPPET FOR MARKER. SNIPPET = " + snippet);
						}
					}
				}
			});

			final Location userLocation = getUserLocation();

			drawMarkersOnMap(userLocation);

			googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
				public void onCameraChange(CameraPosition arg0) {
					if (markers.size() > 0) {
						zoomMapToMarkers(markers);
					} else {
						Log.d(TAG, "No markers defined. Zoom to user location");
						zoomMapToUserLocation(userLocation);
					}
					// Remove listener to prevent position reset on camera move.
					googleMap.setOnCameraChangeListener(null);
				}
			});
		}
	}

	private void zoomMapToMarkers(Collection<MarkerOptions> markers) {
		Log.d(TAG, "Zoom to markers");
		LatLngBounds.Builder builder = new LatLngBounds.Builder();

		for (MarkerOptions marker : markers) {
			builder.include(marker.getPosition());
		}
		Location userLocation = getUserLocation();
		builder.include(new LatLng(userLocation.getLatitude(), userLocation.getLongitude()));

		LatLngBounds bounds = builder.build();

		//obtain a movement description object by using the factory: CameraUpdateFactory:
		int padding = 50; // offset from edges of the map in pixels
		CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);

//		googleMap.moveCamera(cu);
		googleMap.animateCamera(cu);
	}

	private void zoomMapToUserLocation(Location userLocation) {
		if (userLocation != null) {
			System.out.println("LOCATION = " + userLocation.getLatitude() + "/" + userLocation.getLongitude());
			LatLng myLocation = new LatLng(userLocation.getLatitude(), userLocation.getLongitude());
			googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(myLocation, 10));
		} else {
			System.out.println("LOCATION null");
		}
	}

	private Location getUserLocation() {
		LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);//use of location services by firstly defining location manager.
		String provider = lm.getBestProvider(new Criteria(), true);
		return lm.getLastKnownLocation(provider);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	private void drawMarkersOnMap(Location userLocation) {
		Bundle extras = getIntent().getExtras();
		if (extras != null) {

			String searchWordJob = extras.getString("search_word_job");
			String searchCriteriaJob = extras.getString("search_criteria_job");
			String searchProfileJob = extras.getString("search_profile_job");
			String searchDistanceJob = extras.getString("search_distance_job");

			String searchWordCompany = extras.getString("search_word_company");
			String searchCriteriaCompany = extras.getString("search_criteria_company");
			String searchDistanceCompany = extras.getString("search_distance_company");

			if (searchCriteriaJob != null && searchWordJob != null) {
				Log.d(TAG, "Search after jobs with searchCriteria = " + searchCriteriaJob + " and searchWord = " + searchWordJob);

				SearchJobsTask searchCompaniesTask = new SearchJobsTask();
				try {
					Collection<Job> jobsSelection = searchCompaniesTask.execute(searchCriteriaJob, searchWordJob, searchProfileJob).get();
					for (Job job : jobsSelection) {
						LatLng location = new LatLng(job.getLatitude(), job.getLongitude());

						if (isLocationInUserRange(location, userLocation, searchDistanceJob)) {
							jobs.put(job.getId(), job);

							String identifier = "J" + job.getId();
							drawMarker(location, job.getName(), identifier);
						} else {
							Log.d(TAG, "job with name = " + job.getName() + "and id = " + job.getId() + " is not in range for chosen distance");
						}
					}
				} catch (Exception e) {
					Log.e(MainScreenActivity.class.getName(), "Can not get jobs", e);
				}
			} else if (searchCriteriaCompany != null && searchWordCompany != null) {
				Log.d(TAG, "Search after companies with searchCriteria = " + searchCriteriaCompany + " and searchWord = " + searchWordCompany);

				SearchCompaniesTask searchCompaniesTask = new SearchCompaniesTask();
				try {
					Collection<Company> companiesSelection = searchCompaniesTask.execute(searchCriteriaCompany, searchWordCompany).get();
					for (Company company : companiesSelection) {
						if (null != company.getLatitude() && null != company.getLongitude()) {
							LatLng location = new LatLng(company.getLatitude(), company.getLongitude());
							if (isLocationInUserRange(location, userLocation, searchDistanceCompany)) {
								companies.put(company.getId(), company);

								String identifier = "C" + company.getId();
								drawMarker(location, company.getName(), identifier);
							} else {
								Log.d(TAG, "company with name = " + company.getName() + "and id = " + company.getId() + " is not in range for chosen distance");
							}
						}
					}
				} catch (Exception e) {
					Log.e(MainScreenActivity.class.getName(), "Can not get companies", e);
				}
			}
		} else {
			System.out.println("Search = NULL");
		}
	}

	private boolean isLocationInUserRange(LatLng location, Location userLocation, String searchDistance) {
		Location markerLocation = new Location("");
		markerLocation.setLatitude(location.latitude);
		markerLocation.setLongitude(location.longitude);

		float distancePoints = userLocation.distanceTo(markerLocation);

		searchDistance = searchDistance.replace("within ", "");
		searchDistance = searchDistance.replace(" kilometers", "");
		int searchKm = Integer.valueOf(searchDistance) * 1000;

		return distancePoints < searchKm;
	}

	private void drawMarker(LatLng point, String nameMarker, String identifier) {
		// Creating an instance of MarkerOptions
		MarkerOptions markerOptions = new MarkerOptions();

		// Setting latitude and longitude for the marker
		markerOptions.position(point);
		markerOptions.title(nameMarker);
		markerOptions.snippet(identifier);

		// Adding marker on the Google Map
		googleMap.addMarker(markerOptions);

		markers.add(markerOptions);
	}

	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == 1234 && resultCode == RESULT_OK) {
			ArrayList<String> matches = data
					.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);

			WordMatcher objectsMatcher = new WordMatcher(Arrays.asList("company", "job"));
			WordMatcher actionsMatcher = new WordMatcher(Arrays.asList("add", "search"));
			if (0 == matches.size()) {
				System.out.println("matches number is 0");
			} else {

				for (int i = 0; i < matches.size(); i++) {
					String item = matches.get(i);
					item = item.toLowerCase();

					WordList words = new WordList(item);

					String searchAfterObject = objectsMatcher.isIn(words.getWords());
					String searchAfterAction = actionsMatcher.isIn(words.getWords());
					if (null != searchAfterAction && null != searchAfterObject) {
						if (searchAfterAction.equals("search")) {
							if (searchAfterObject.equals("job")) {
								Intent intent = new Intent(MainScreenActivity.this,
										SearchJobActivity.class);
								startActivity(intent);
							} else if (searchAfterObject.equals("company")) {
								Intent intent = new Intent(MainScreenActivity.this,
										SearchCompanyActivity.class);
								startActivity(intent);
							}

						}
					}
				}
			}
			;
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

}